#ifndef __VALUE_HELPER_H__
#define __VALUE_HELPER_H__

#include "math/math_config.h"
#include "math/math_def.h"
#include "math/array/array.h"
#include "math/complex.h"
#include "math/xobject.h"

NS_MATH_BEGIN

typedef XObject xobject;
typedef array<XObject> arr_object;

template<typename T>
class TypeInfoT
{
public:
	static const int id = 0;
};

template<int TYPEID>
class ID2TypeT
{
public:
	typedef void type0;
};

#define __TMPL_TYPEINFO_ID_SETTING__(TYPE, TYPEID) \
template<> \
class TypeInfoT<TYPE> \
{ \
public: \
	static const int id = TYPEID; \
}; \
template<> \
class ID2TypeT<TYPEID> \
{ \
public: \
	typedef TYPE type0; \
};

__TMPL_TYPEINFO_ID_SETTING__(void, 0);
__TMPL_TYPEINFO_ID_SETTING__(bool, 1);
__TMPL_TYPEINFO_ID_SETTING__(int32, 2);
__TMPL_TYPEINFO_ID_SETTING__(int64, 3);
__TMPL_TYPEINFO_ID_SETTING__(float32, 4);
__TMPL_TYPEINFO_ID_SETTING__(float64, 5);
__TMPL_TYPEINFO_ID_SETTING__(complex32, 8);
__TMPL_TYPEINFO_ID_SETTING__(complex64, 9);
__TMPL_TYPEINFO_ID_SETTING__(xstring, 16);
__TMPL_TYPEINFO_ID_SETTING__(arr_bool, 64 + 1);
__TMPL_TYPEINFO_ID_SETTING__(arr_int32, 64 + 2);
__TMPL_TYPEINFO_ID_SETTING__(arr_int64, 64 + 3);
__TMPL_TYPEINFO_ID_SETTING__(arr_float32, 64 + 4);
__TMPL_TYPEINFO_ID_SETTING__(arr_float64, 64 + 5);
__TMPL_TYPEINFO_ID_SETTING__(arr_complex32, 64 + 8);
__TMPL_TYPEINFO_ID_SETTING__(arr_complex64, 64 + 9);
__TMPL_TYPEINFO_ID_SETTING__(arr_string, 64 + 16);
__TMPL_TYPEINFO_ID_SETTING__(xobject, 32);
__TMPL_TYPEINFO_ID_SETTING__(arr_object , 64 + 32); 

#undef __TMPL_TYPEINFO_ID_SETTING__

template<int V0, int V1>
class __TYPEID_COMPARE__
{
public:
	static const int __min__ = (V0<V1)?V0:V1;
	static const int __max__ = (V1>V0)?V1:V0;
};

template<typename T0, typename T1>
class __TYPE_COMPARE__
{
public:
	typedef typename ID2TypeT<__TYPEID_COMPARE__<TypeInfoT<T0>::id, TypeInfoT<T1>::id >::__min__ >::type0 type0;
	typedef typename ID2TypeT<__TYPEID_COMPARE__<TypeInfoT<T0>::id, TypeInfoT<T1>::id >::__max__ >::type0 type1;
};


// Type Compo-op Calculator
template<typename T0, typename T1>
class TypeCompT
{
public:
	typedef T0 type0;
	typedef T1 type1;
	typedef void target_type;
};

template<typename T>
class TypeCompT<T, T>
{
public:
	typedef T type0;
	typedef T type1;
	typedef T target_type;
};

#define TYPECOMP_IMPL(TA, TB, TT) \
template<> \
class TypeCompT<TA, TB> \
{ \
public: \
	typedef TA type0; \
	typedef TB type1; \
	typedef TT target_type; \
}; \
template<> \
class TypeCompT<TB, TA> \
{ \
public: \
	typedef TB type0; \
	typedef TA type1; \
	typedef TT target_type; \
}; \

TYPECOMP_IMPL(void, bool, void);
TYPECOMP_IMPL(void, int64, void);
TYPECOMP_IMPL(void, float64, void);
TYPECOMP_IMPL(void, complex64, void);
TYPECOMP_IMPL(void, xstring, void);
TYPECOMP_IMPL(void, arr_bool, void);
TYPECOMP_IMPL(void, arr_int64, void);
TYPECOMP_IMPL(void, arr_float64, void);
TYPECOMP_IMPL(void, arr_complex64, void);
TYPECOMP_IMPL(void, arr_string, void);

TYPECOMP_IMPL(bool, int64, int64);
TYPECOMP_IMPL(bool, float64, float64);
TYPECOMP_IMPL(bool, complex64, complex64);
TYPECOMP_IMPL(bool, xstring, void);
TYPECOMP_IMPL(bool, arr_bool, arr_bool);
TYPECOMP_IMPL(bool, arr_int64, arr_int64);
TYPECOMP_IMPL(bool, arr_float64, arr_float64);
TYPECOMP_IMPL(bool, arr_complex64, arr_complex64);
TYPECOMP_IMPL(bool, arr_string, void);

TYPECOMP_IMPL(int64, float64, float64);
TYPECOMP_IMPL(int64, complex64, complex64);
TYPECOMP_IMPL(int64, xstring, void);
TYPECOMP_IMPL(int64, arr_bool, arr_int64);
TYPECOMP_IMPL(int64, arr_int64, arr_int64);
TYPECOMP_IMPL(int64, arr_float64, arr_float64);
TYPECOMP_IMPL(int64, arr_complex64, arr_complex64);
TYPECOMP_IMPL(int64, arr_string, void);

TYPECOMP_IMPL(float64, complex64, complex64);
TYPECOMP_IMPL(float64, xstring, void);
TYPECOMP_IMPL(float64, arr_bool, arr_float64);
TYPECOMP_IMPL(float64, arr_int64, arr_float64);
TYPECOMP_IMPL(float64, arr_float64, arr_float64);
TYPECOMP_IMPL(float64, arr_complex64, arr_complex64);
TYPECOMP_IMPL(float64, arr_string, void);

TYPECOMP_IMPL(complex64, xstring, void);
TYPECOMP_IMPL(complex64, arr_bool, arr_complex64);
TYPECOMP_IMPL(complex64, arr_int64, arr_complex64);
TYPECOMP_IMPL(complex64, arr_float64, arr_complex64);
TYPECOMP_IMPL(complex64, arr_complex64, arr_complex64);
TYPECOMP_IMPL(complex64, arr_string, void);

TYPECOMP_IMPL(xstring, arr_bool, void);
TYPECOMP_IMPL(xstring, arr_int64, void);
TYPECOMP_IMPL(xstring, arr_float64, void);
TYPECOMP_IMPL(xstring, arr_complex64, void);
TYPECOMP_IMPL(xstring, arr_string, arr_string);

TYPECOMP_IMPL(arr_bool, arr_int64, arr_int64);
TYPECOMP_IMPL(arr_bool, arr_float64, arr_float64);
TYPECOMP_IMPL(arr_bool, arr_complex64, arr_complex64);
TYPECOMP_IMPL(arr_bool, arr_string, void);

TYPECOMP_IMPL(arr_int64, arr_float64, arr_float64);
TYPECOMP_IMPL(arr_int64, arr_complex64, arr_complex64);
TYPECOMP_IMPL(arr_int64, arr_string, void);

TYPECOMP_IMPL(arr_float64, arr_complex64, arr_complex64);
TYPECOMP_IMPL(arr_float64, arr_string, void);

TYPECOMP_IMPL(arr_complex64, arr_string, void);

#undef TYPECOMP_IMPL

// Type Operation
//

template<typename T1, typename T2>
class TypePromotionT
{
public:
	typedef void type;
};

template<typename T>
class TypePromotionT<T,T>
{
public:
	typedef T type;
};

template<typename T1, typename T2>
class TypePromotionT<array<T1>, T2>
{
public:
	typedef array<TypePromotionT<T1,T2> > type;
};

template<typename T1, typename T2>
class TypePromotionT<T1, array<T2> >
{
public:
	typedef array<TypePromotionT<T1,T2> > type;
};

template<typename T1, typename T2>
class TypePromotionT<array<T1>, array<T2> >
{
public:
	typedef array<TypePromotionT<T1,T2> > type;
};

#define _TYPEPROMOTION_DEF_(T1,T2,T3) \
template<> \
class TypePromotionT<T1,T2> \
{ \
public: \
	typedef T3 type; \
}; \
template<> \
class TypePromotionT<T2,T1> \
{ \
public: \
	typedef T3 type; \
};

_TYPEPROMOTION_DEF_(bool, int32, int32);
_TYPEPROMOTION_DEF_(bool, int64, int64);
_TYPEPROMOTION_DEF_(bool, float32, float32);
_TYPEPROMOTION_DEF_(bool, float64, float64);
_TYPEPROMOTION_DEF_(bool, complex32, complex32);
_TYPEPROMOTION_DEF_(bool, complex64, complex64);
_TYPEPROMOTION_DEF_(int32, int64, int64);
_TYPEPROMOTION_DEF_(int32, float32, float32);
_TYPEPROMOTION_DEF_(int32, float64, float64);
_TYPEPROMOTION_DEF_(int32, complex32, complex32);
_TYPEPROMOTION_DEF_(int32, complex64, complex64);
_TYPEPROMOTION_DEF_(int64, float32, float64);
_TYPEPROMOTION_DEF_(int64, float64, float64);
_TYPEPROMOTION_DEF_(int64, complex32, complex64);
_TYPEPROMOTION_DEF_(int64, complex64, complex64);
_TYPEPROMOTION_DEF_(float32, float64, float64);
_TYPEPROMOTION_DEF_(float32, complex32, complex32);
_TYPEPROMOTION_DEF_(float32, complex64, complex64);
_TYPEPROMOTION_DEF_(float64, complex32, complex64);
_TYPEPROMOTION_DEF_(float64, complex64, complex64);


#undef _TYPEPROMOTION_
NS_MATH_END
#endif